package controller;
/*
 * Copyright (c) 2007, Sun Microsystems, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of Sun Microsystems, Inc. nor the names of its contributors
 *   may be used to endorse or promote products derived from this software without
 *   specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

import modelo.Datospersonales;
import modelo.Usuario;
import java.util.List;
import java.util.Vector;
import javax.annotation.Resource;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
import javax.persistence.Query;
import javax.servlet.http.HttpSession;
import javax.transaction.UserTransaction;

/**
 * <p>Un unico bean de manejo para mediar entre el usuario y la persistencia
 * .</p>
 * @author rlubke & modified by cgomez
 */
public class UserManager {
    
    /**
     * <p>El atributo clave para el ambito de sesion que almacena
     *la instancia apropiada de <code>Usuario</code>.</p>
     */
    public static final String USER_SESSION_KEY = "user";
    
    @PersistenceUnit(unitName = "sistemaReservaPU")
    private EntityManagerFactory emf = null;
    
    /**
     * <p>El recurso de transaccion.</p>
     */
    @Resource 
    private UserTransaction utx;

    /**
     * <p>El <code>PersistenceContext</code>.</p>
     */
    @PersistenceContext 
    private EntityManager em;
    //variable que contiene el user id de la sesion actual
    private String username;
    //variable auxiliar que contiene el user id de la sesion previa
    private String usernameAux;
    //variable que contiene el password de la sesion actual
    private String password;
    //variable auxiliar que contiene la nueva contraseña de un cambio de contraseña
    private String newpassword;
    //variable auxiliar que contiene confirmacion de contraseña de un cambio de contraseña
    private String confirmpassword;
    // POJO de DatosPersonales Representada.
    private Datospersonales datospersonales = null;
    // Lista de DatosPersonales
    private List<Datospersonales> datospersonaless = null;
    // variable auxiliar utilizado como contador de elementos
    private int itemCount = -1;
    // variable auxiliar para indicar el 1er elemento
    private int firstItem = 0;
    // variable auxiliar que indica el tamaño de conjunto
    public int batchSize = 100;
    
    // -------------------------------------------------------------- Properties
    /**
     * metodo publico para obtener el username
     * @return String
     */    
    public String getUsername() {
        return username;
    }
    /**
     * metodo publico para fijar el username
     * @param username cadena que contiene el username
     */    
    public void setUsername(String username) {
        this.username = username;
    }
     /**
     * metodo publico para obtener el password de la sesion
     * @return String
     */   
    public String getPassword() {
        return password;
    }
    /**
     * metodo publico para fijar el password de la session
     * @param password que contiene el password de la sesion
     */    
    public void setPassword(String password) {
        this.password = password;
    }
    /**
     * metodo publico para obtener la confirmacion del password
     * @return String
     */    
    public String getConfirmpassword() {
        return confirmpassword;
    }
    /**
     * metodo publico para la confirmacion de password
     * @param confirmpassword String que contiene la confirmacion del password
     */
    public void setConfirmpassword(String confirmpassword) {
        this.confirmpassword = confirmpassword;
    }
    /**
     * metodo publico para el nuevo password a ser cambiado
     * @return String
     */
    public String getNewpassword() {
        return newpassword;
    }
    /**
     * metodo publico para fijar el nuevo password a ser cambiado
     * @param newpassword String que contiene el nuevo password
     */
    public void setNewpassword(String newpassword) {
        this.newpassword = newpassword;
    }
    // ---------------------------------------------------------- Public Methods
    
    
    /**
     * <p>Valida el usuario.  Si el usuario no existe o la contraseña
     * es incorrecta, se agrega al contexto <code>FacesContext</code> el mensaje apropiado
     * Si el usuario se autentica exitosamente,
     * lo lleva a la pagina referenciada por el outcome <code>app-main</code>.
     * </p>
     *@return <code>app-main</code> si el usuario se autentica, de otra forma
     *  retorna <code>null</code>
     */
    public String validateUser() {
        autoLogout();
        FacesContext context = FacesContext.getCurrentInstance();
        Usuario user = getUser();
        if (user != null) {
            if (!user.getContrasenha().equals(password)) {
                FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                                           "Login Fallido!",
                                           "El password ingresado es incorrecto.");
                context.addMessage(null, message);
                this.insertarAuditoria(username,"login", "el password ingresado es incorrecto");
                return null;
            }else if (!user.getEstado()){
                FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                                           "Login Fallido!",
                                           "El su usuario ha sido deshabilitado.");
                context.addMessage(null, message);
                this.insertarAuditoria(username,"login", "usuario deshabilitado");
                return null;                
            }
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
                                           "Usuario conectado","Ha ingresado al Sistema.");
            context.addMessage(null, message);
            context.getExternalContext().getSessionMap().put(USER_SESSION_KEY, user);
            this.insertarAuditoria(username,"login", "login exitoso");
            return "app-main";
        } else {           
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                    "Login Fallido!",
                    "ID de Usuario '"
                    + username
                    +
                    "' no existe.");
            this.insertarAuditoria(username,"login", "usuario no existe");
            context.addMessage(null, message);
            return null;
        }
    }
    
    /**
     * <p>Cuando sea invocado, invalidará la sesión del usuario
     * y lo llevara a la vista del login.</p>
     *@return <code>login</code>
     */
    public String logout() {
        HttpSession session = (HttpSession)
             FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        Usuario user = (Usuario) session.getAttribute("user");
        username = user.getIdUsuario();
        this.insertarAuditoria(username, "logout", "usuario se ha desconectado");
        if (session != null) {
            session.invalidate();
        }
        return "login";
        
    }
    
        /**
     * <p>Cuando sea invocado, invalidará la sesión del usuario
     * </p>
     */
    public void autoLogout() {
        try {
            HttpSession session = (HttpSession)
                FacesContext.getCurrentInstance().getExternalContext().getSession(false);
            if (session != null) {
                Usuario user = (Usuario) session.getAttribute("user");
                usernameAux = user.getIdUsuario();
                this.insertarAuditoria(usernameAux,"logout", "usuario se ha desconectado");            
                session.invalidate();
            }
        }catch (Exception e){
            return;
        }
    }
    
    // --------------------------------------------------------- Private Methods
    
    
    /**
     * <p>Este intentara buscar al objeto <code>Usuario</code> 
     * basado en el ID Usuario provisto.</p>
     *
     * @return un objeto <code>Usuario</code> asociado con el username actual
     *  de otra forma, si no puede ser encontrado un objeto <code>Usuario</code>,
     *  retorna <code>null</code>
     */
    private Usuario getUser() {
        try {
            Usuario user = (Usuario)
            em.createNamedQuery("Usuario.findByIdUsuario").
                    setParameter("idUsuario", username).getSingleResult();
            user.setContrasenha(getPassword(username));
            return user; 
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    /**
     * Metodo que inserta un nuevo registro de auditoria de login
     * @param username contiene el username del usuario
     * @param operacion contiene la operacion realizada (login, logout)
     * @param mensaje contiene el mensaje enviado
     */
    private void insertarAuditoria(String username, String operacion, String mensaje){
        EntityManager em = getEntityManager();
        String SQL = "select f_insertar_auditoria_acceso('"+username+"','"+operacion+"','"+mensaje+"')";
        Query q = em.createNativeQuery(SQL);
        Vector v = new Vector();
        v = (Vector) q.getSingleResult();
    }
    
    /**
     * Getter del Administrador de Entidades.
     * @return EntityManager
     */    
    public EntityManager getEntityManager() {
        return emf.createEntityManager();
    }

    /**
     * Metodo que realiza las operaciones de cambio de contraseña del usuario
     * @return String TAG de la pagina siguiente
     */
    public String changePassword() {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpSession session = (HttpSession) 
                FacesContext.getCurrentInstance().getExternalContext().getSession(false);
        Usuario user = (Usuario) session.getAttribute("user");
        if (user != null) {
            if (!user.getContrasenha().equals(password)) {
                FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                                           "Cambio de Contraseña fallido!",
                                           "La contraseña actual es incorrecto.");
                context.addMessage(null, message);
                return null;
            }
            if (!newpassword.equals(confirmpassword)) {
                FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                                           "Cambio de Contraseña fallido!",
                                           "La nueva contraseña y la confirmacion no coinciden.");
                context.addMessage(null, message);
                return null;
            }else if(newpassword.length()<5){
                FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                        "Cambio de Contraseña fallido!",
                        "La nueva contraseña debe tener al menos 5 caracteres.");
                context.addMessage(null, message);
                return null;
            }
            String mensaje = changePersitancePassword(user);
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
                                           "Contraseña cambiada exitosamente","Cambio Exitoso.");
            context.addMessage(null, message);
            user.setContrasenha(newpassword);
            context.getExternalContext().getSessionMap().put(USER_SESSION_KEY, user);

            return "menuAdminPerfil";
        } else {           
            FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
                    "Cambio de Contraseña Fallido!",
                    "La sesion actual ha expirado");
            context.addMessage(null, message);
            return null;
        }
    }
    /**
     * Metodo para inicializar las operaciones de cambio de password
     * @return String con el TAG
     */
    public String changeSetup(){
            return "cambiar_passord";
    }
    /**
     * Metodo que cambia la contraseña en la base de datos
     * @param user username
     * @return String Mensaje de confirmacion de cambios
     */
    private String changePersitancePassword(Usuario user){
        EntityManager em = getEntityManager();
        String SQL = "select f_cambiar_password('"+user.getIdUsuario()+"','"+newpassword+"')";
        Query q = em.createNativeQuery(SQL);
        Vector v = new Vector();
        v = (Vector) q.getSingleResult();
        String s = (String)v.get(0);
        return s;
    }
    
        /**
     * Metodo que obtener la contraseña en la base de datos
     * @param user username
     * @return String Mensaje de confirmacion de cambios
     */
    private String getPassword(String user){
        EntityManager em = getEntityManager();
        String SQL = "select usuario.contrasenha from usuario where usuario.idusuario ='"+user+"'";
        Query q = em.createNativeQuery(SQL);
        Vector v = new Vector();
        v = (Vector) q.getSingleResult();
        String s = (String)v.get(0);
        return s;
    }
}

